<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 * @author   howe <howe1995@163.com>
 */

namespace App\Exception\Handler;

use App\Constant\ApiCodeEnum;
use App\Exception\BusinessException;
use App\Model\ExceptionLog;
use App\Support\Traits\ServiceException;
use Hyperf\Contract\StdoutLoggerInterface;
use Hyperf\Database\Model\ModelNotFoundException;
use Hyperf\ExceptionHandler\ExceptionHandler;
use Hyperf\HttpMessage\Exception\MethodNotAllowedHttpException;
use Hyperf\HttpMessage\Exception\NotFoundHttpException;
use Hyperf\Validation\ValidationException;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Throwable;

use function Hyperf\Config\config;

class AppExceptionHandler extends ExceptionHandler
{
    use ServiceException;

    public function __construct(protected StdoutLoggerInterface $logger, protected ServerRequestInterface $request)
    {
    }

    public function handle(Throwable $throwable, ResponseInterface $response)
    {
        $this->logger->debug($throwable);
        $exString = sprintf('%s[%s] in %s', $throwable->getMessage(), $throwable->getLine(), $throwable->getFile());
        // $this->logger->error($exString);
        // $this->logger->error($throwable->getTraceAsString());

        $data = [
            'env' => config('app_env'),
            'project' => config('app_name'),
            'url' => $this->request->getUri()->getPath(),
            'request_ip' => getClientIp(),
            'request_id' => $this->request->input('request_id') ?? uniqid(),
            'exception' => $exString,
            'created_at' => date('Y-m-d H:i:s'),
        ];
        ExceptionLog::create($data);

        // 参数校验错误异常抛出
        if ($throwable instanceof ValidationException) {
            $error = $throwable->validator->errors()->first();
            return response()->json([
                'code' => $this->parseErrorCode(ApiCodeEnum::CLIENT_PARAMETER_ERROR),
                'msg' => $this->parseErrorMessage(ApiCodeEnum::CLIENT_DATA_NOT_FOUND, $error),
                // 'file' => $throwable->getFile(),
                // 'line' => $throwable->getLine(),
                // 'data' => null
            ]);
        }
        if ($throwable instanceof ModelNotFoundException) {
            // Model 查不到数据
            return response()->json([
                'code' => $this->parseErrorCode(ApiCodeEnum::CLIENT_DATA_NOT_FOUND),
                'msg' => $this->parseErrorMessage(ApiCodeEnum::CLIENT_DATA_NOT_FOUND, $throwable->getMessage()),
                // 'file' => $throwable->getFile(),
                // 'line' => $throwable->getLine(),
                // 'data' => null
            ]);
        }
        if ($throwable instanceof MethodNotAllowedHttpException) {
            // 请求地址不存在
            return response()->json([
                'code' => $this->parseErrorCode(ApiCodeEnum::CLIENT_METHOD_HTTP_TYPE_ERROR),
                'msg' => $this->parseErrorMessage(ApiCodeEnum::CLIENT_METHOD_HTTP_TYPE_ERROR, $throwable->getMessage()),
                // 'file' => $throwable->getFile(),
                // 'line' => $throwable->getLine(),
                // 'data' => null
            ]);
        }
        if ($throwable instanceof NotFoundHttpException) {
            // 请求地址不存在
            return response()->json([
                'code' => $this->parseErrorCode(ApiCodeEnum::CLIENT_METHOD_HTTP_RUL_ERROR),
                'msg' => $this->parseErrorMessage(ApiCodeEnum::CLIENT_METHOD_HTTP_RUL_ERROR, $throwable->getMessage()),
                // 'file' => $throwable->getFile(),
                // 'line' => $throwable->getLine(),
                // 'data' => null
            ]);
        }
        if ($throwable instanceof BusinessException) {
            // 自定义错误异常抛出
            return response()->json([
                'code' => $throwable->getCode(),
                // 'msg' => $throwable->getMessage() . '[' . $throwable->getLine() . ']' . $throwable->getFile(),
                'msg' => $throwable->getMessage(),
                // 'file' => $throwable->getFile(),
                // 'line' => $throwable->getLine(),
                // 'data' => null
            ]);
        }
        var_dump($throwable->getMessage() . 'config error');
        return response()->json([
            'code' => $this->parseErrorCode(ApiCodeEnum::SYSTEM_ERROR),
            // 'msg' => $throwable->getMessage() . '[' . $throwable->getLine() . ']' . $throwable->getFile(),
            'msg' => $throwable->getMessage(),
            // 'file' => $throwable->getFile(),
            // 'line' => $throwable->getLine(),
            // 'data' => null
        ]);

        // return $response->withHeader('Server', 'Hyperf')->withStatus(500)->withBody(new SwooleStream('Internal Server Error.'));
    }

    public function isValid(Throwable $throwable): bool
    {
        return true;
    }
}
